<template>
  <el-date-picker
    v-model="innerValue"
    type="date"
    :placeholder="placeholder"
    :format="format"
    @focus="onFocus"
    @blur="onBlur"
  ></el-date-picker>
</template>

<script>
import { domHasClass } from '@vimi/utils-tool'

const isPickedEqual = (a, b) => {
  if (a.length !== b.length) {
    return false
  }

  for (let i = 0; i < 3; i++) {
    if (!a[i] && !b[i]) return true
    if (a[i] !== b[i]) {
      return false
    }
  }
  return true
}

const formatYear = 'yyyy'
const formatMonth = 'yyyy-M'
const formatDate = 'yyyy-M-d'

const viewYear = 'year'
const viewMonth = 'month'
const viewDate = 'date'

export default {
  components: {},
  props: {
    // [year, month, day]
    value: Array,
    placeholder: {
      type: String,
      default: '选择日期',
    },
  },
  model: {
    prop: 'value',
    event: 'select',
  },
  data() {
    return {
      innerValue: '',
      picker: null,
      currentView: viewYear,

      format: formatYear,
      picked: [],
    }
  },
  computed: {},
  watch: {
    value: {
      handler: function (val) {
        if (isPickedEqual(this.picked, val)) {
          return
        }

        this.picked = val
        this.innerValue = this.valueParse(val)

        const { format, view } = this.viewParse(val)
        this.currentView = view
        this.format = format
      },
      immediate: true,
    },
  },
  created() {},
  mounted() {},
  methods: {
    async onFocus() {
      await this.getPicker()

      if (!this.innerValue) {
        return this.picker.showYearPicker()
      }

      switch (this.currentView) {
        case viewYear:
          this.picker.showYearPicker()
          break
        case viewMonth:
          this.picker.showMonthPicker()
          break
        default:
          break
      }
    },

    getPicker() {
      return new Promise((resolve, reject) => {
        if (this.picker) {
          return resolve(this.picker)
        }

        this.$nextTick(() => {
          const { picker } = this.$children[0]
          if (!picker) {
            return reject(new Error())
          }

          picker.$on('pick', (date = '') => {
            this.onPick(date, viewDate)
          })

          const yearTable = picker.$children.find(child => domHasClass(child.$el, 'el-year-table'))
          yearTable &&
            yearTable.$on('pick', year => {
              this.onPick(year, viewYear)
            })

          const monthTable = picker.$children.find(child =>
            domHasClass(child.$el, 'el-month-table')
          )
          monthTable &&
            monthTable.$on('pick', month => {
              this.onPick(month, viewMonth)
            })

          this.picker = picker
          resolve(picker)
        })
      })
    },

    onPick(date, type) {
      const [year, month] = this.picked
      switch (type) {
        case viewYear:
          this.format = formatYear
          this.picked = [date]
          this.currentView = viewYear
          break
        case viewMonth:
          this.format = formatMonth
          this.picked = [year, date + 1]
          this.currentView = viewMonth
          break
        case viewDate: {
          if (date) {
            this.format = formatDate
            this.picked = [year, month, new Date(date).getDate()]
          } else {
            this.format = formatYear
            this.picked = []
          }
          this.currentView = viewDate
          break
        }
        default:
          break
      }

      this.emit(this.picked)
    },

    emit(val) {
      this.innerValue = this.valueParse(val)
      this.$emit('select', val)
    },

    valueParse(val) {
      return val.join('-')
    },

    viewParse(val) {
      const { length } = val
      const enumView = {
        0: { format: formatYear, view: viewYear },
        1: { format: formatYear, view: viewMonth },
        2: { format: formatMonth, view: viewDate },
        3: { format: formatDate, view: viewDate },
      }
      return enumView[length] || { format: formatDate, view: viewDate }
    },

    onBlur(e) {
      this.$emit('blur', e)
    },
  },
}
</script>

<style lang="scss" scoped></style>
